<template>
	<div ref='CKEditorContainerRef' class='CKEditor-container'
		 data-theme='' data-editor='DecoupledEditor-A4'>
		<!--工具栏-->
		<div ref='CKToolBarRef' class='toolbar'></div>
		<!--编辑器外框-->
		<div class='row-editor'>
			<!--编辑器内框-->
			<div class='editor-container'>
				<!--编辑器-->
				<div ref='CKEditorRef' class='editor'></div>
			</div>
		</div>
	</div>
</template>
<script setup lang='ts'>
import { computed, onMounted, reactive, ref, watch } from 'vue';
import { Editor, EditorConfig } from '@ckeditor/ckeditor5-core';
import CKSource from 'ckeditor5-full-build';
import { EditorWatchdog } from '@ckeditor/ckeditor5-watchdog';
import { useCommonStore } from '@/config/pinia/common.store.ts';
const props = defineProps({
	editorConfig : {
		type    : Object,
		require : true
	},
	readOnly     : {
		type    : Boolean,
		require : true,
		default : false
	}
});
const initValue = defineModel<string>('initValue');
const htmlValue = defineModel<string>('htmlValue');
const commonStore = useCommonStore();
// 编辑器默认配置
const CKEditorConfig: EditorConfig = reactive({
	language : 'zh-cn',
	heading  : {
		options : [
			{ model : 'paragraph', title : 'Paragraph', class : 'ck-heading_paragraph' },
			{ model : 'heading1', view : 'h1', title : 'Heading 1', class : 'ck-heading_heading1' },
			{ model : 'heading2', view : 'h2', title : 'Heading 2', class : 'ck-heading_heading2' },
			{ model : 'heading3', view : 'h3', title : 'Heading 3', class : 'ck-heading_heading3' }
		]
	}
});
const CKEditorContainerRef = ref();
const CKEditorRef = ref();
const CKToolBarRef = ref();
let editorInstance: any = null;
let editorWatchdogInstance: any = null;
const theme = computed(() => commonStore.theme);
onMounted(() => {
	CKEditorContainerRef.value.setAttribute('data-theme', theme.value);
	initWatchDog();
});
watch(initValue, (newValue, oldValue) => {
	if (editorInstance) {
		if (newValue) {
			editorInstance.setData(newValue);
		} else {
			editorInstance.setData('');
		}
	}
}, {
	deep      : false,
	immediate : false
});
watch(theme, (newValue, oldValue) => {
	switch (newValue) {
		case 'dark':
			CKEditorContainerRef.value.setAttribute('data-theme', 'dark');
			break;
		case 'light':
			CKEditorContainerRef.value.setAttribute('data-theme', 'light');
			break;
	}
}, {
	deep      : false,
	immediate : false
});
const initWatchDog = async () => {
	// 如果使用者传递了编辑器配置,则将其合并
	if (props.editorConfig) {
		Object.assign(CKEditorConfig, props.editorConfig);
	}
	// @ts-ignore
	editorWatchdogInstance = new CKSource.EditorWatchdog();
	setCreator(editorWatchdogInstance);
	setDestructor(editorWatchdogInstance);
	editorWatchdogInstance.on('error', handleSampleError);
	editorWatchdogInstance.create(CKEditorRef.value, CKEditorConfig).catch(handleSampleError);
};
const setCreator = (watchdog: EditorWatchdog) => {
	watchdog.setCreator((element, config) => {
		// @ts-ignore
		return CKSource.Editor.create(CKEditorRef.value, CKEditorConfig)
					   .then((editor: Editor) => {
						   editorInstance = editor;
						   // 监听编辑器内容修改事件
						   editor.model.document.on('change:data', onChangeData);
						   // 加载初始绑定数据
						   if (initValue.value) {
							   // @ts-ignore
							   editor.setData(initValue.value);
						   }
						   // 设置一个自定义容器到toolbar.
						   if (CKToolBarRef.value) {
							   // @ts-ignore
							   CKToolBarRef.value.appendChild(editor.ui.view.toolbar.element);
						   }
						   const toolbarElement: Element | null = CKToolBarRef.value.querySelector('.ck-toolbar');
						   if (toolbarElement) {
							   toolbarElement.classList.add('ck-reset_all');
						   }
						   if (props['readOnly']) {
							   editor.enableReadOnlyMode(editor.id);
						   }
						   return editor;
					   });
	});
};
const setDestructor = (watchdog: EditorWatchdog) => {
	watchdog.setDestructor((editor: Editor) => {
		// 清除onChangeData的事件监听
		editor?.model?.document?.off('change:data', onChangeData);
		// 销毁掉编辑器对象
		return editor?.destroy();
	});
};
const onChangeData = () => {
	// 将他返回给htmlValue
	htmlValue.value = editorInstance.getData();
};
const clearText = async () => {
	editorInstance.setData('');
};
const setData = async (richTextContent: string) => {
	editorInstance.setData(richTextContent);
};
const handleSampleError = (error: any) => {
	const issueUrl = 'https://github.com/ckeditor/ckeditor5/issues';
	const message = [
		'哎呀,出错误了!',
		`请在${issueUrl}上报告以下错误，构建id为“wlz0wuzfzauw-u1dflq2m9bb3”和错误堆栈跟踪:`
	].join('\n');
	console.error(message);
	console.error(error);
};
defineExpose({ editorInstance, clearText, setData });
</script>
<style scoped lang='scss'>
.CKEditor-container[data-theme='dark'][data-editor='DecoupledEditor-A4']{
	/* Overrides the border radius setting in the theme. */
	--ck-border-radius                            :2px;
	/* Overrides the default font size in the theme. */
	--ck-font-size-base                           :13px;
	/* Helper variables to avoid duplication in the colors. */
	--ck-base-text-color                          :rgba(0, 0, 0, 1);
	--ck-paper-background                         :hsl(0, 0%, 100%);
	--ck-custom-background                        :rgba(0, 0, 0, 1);
	--ck-custom-foreground                        :hsl(255, 3%, 18%);
	--ck-custom-border                            :hsl(300, 1%, 22%);
	--ck-custom-white                             :hsl(0, 0%, 100%);
	/* -- Overrides generic colors. ------------------------------------------------------------- */
	--ck-color-base-text                          :hsl(0, 0%, 20%);
	--ck-color-base-foreground                    :var(--ck-custom-background);
	--ck-color-focus-border                       :hsl(208, 90%, 62%);
	--ck-color-text                               :hsl(0, 0%, 98%);
	--ck-color-shadow-drop                        :hsla(0, 0%, 0%, 0.2);
	--ck-color-shadow-inner                       :hsla(0, 0%, 0%, 0.1);
	/* -- Overrides the default .ck-button class colors. ---------------------------------------- */
	--ck-color-button-default-background          :var(--ck-custom-background);
	--ck-color-button-default-hover-background    :hsl(270, 1%, 22%);
	--ck-color-button-default-active-background   :hsl(270, 2%, 20%);
	--ck-color-button-default-active-shadow       :hsl(270, 2%, 23%);
	--ck-color-button-default-disabled-background :var(--ck-custom-background);
	--ck-color-button-on-background               :var(--ck-custom-foreground);
	--ck-color-button-on-hover-background         :hsl(255, 4%, 16%);
	--ck-color-button-on-active-background        :hsl(255, 4%, 14%);
	--ck-color-button-on-active-shadow            :hsl(240, 3%, 19%);
	--ck-color-button-on-disabled-background      :var(--ck-custom-foreground);
	--ck-color-button-action-background           :hsl(168, 76%, 42%);
	--ck-color-button-action-hover-background     :hsl(168, 76%, 38%);
	--ck-color-button-action-active-background    :hsl(168, 76%, 36%);
	--ck-color-button-action-active-shadow        :hsl(168, 75%, 34%);
	--ck-color-button-action-disabled-background  :hsl(168, 76%, 42%);
	--ck-color-button-action-text                 :var(--ck-custom-white);
	--ck-color-button-save                        :hsl(120, 100%, 46%);
	--ck-color-button-cancel                      :hsl(15, 100%, 56%);
	/* -- Overrides the default .ck-dropdown class colors. -------------------------------------- */
	--ck-color-dropdown-panel-background          :var(--ck-custom-background);
	--ck-color-dropdown-panel-border              :var(--ck-custom-foreground);
	/* -- Overrides the default .ck-splitbutton class colors. ----------------------------------- */
	--ck-color-split-button-hover-background      :var(--ck-color-button-default-hover-background);
	--ck-color-split-button-hover-border          :var(--ck-custom-foreground);
	/* -- Overrides the default .ck-input class colors. ----------------------------------------- */
	--ck-color-input-background                   :var(--ck-custom-background);
	--ck-color-input-border                       :hsl(257, 3%, 43%);
	--ck-color-input-text                         :hsl(0, 0%, 98%);
	--ck-color-input-disabled-background          :hsl(255, 4%, 21%);
	--ck-color-input-disabled-border              :hsl(250, 3%, 38%);
	--ck-color-input-disabled-text                :hsl(0, 0%, 78%);
	/* -- Overrides the default .ck-labeled-field-view class colors. ---------------------------- */
	--ck-color-labeled-field-label-background     :var(--ck-custom-background);
	/* -- Overrides the default .ck-list class colors. ------------------------------------------ */
	--ck-color-list-background                    :var(--ck-custom-background);
	--ck-color-list-button-hover-background       :var(--ck-custom-foreground);
	--ck-color-list-button-on-background          :hsl(208, 88%, 52%);
	--ck-color-list-button-on-text                :var(--ck-custom-white);
	/* -- Overrides the default .ck-balloon-panel class colors. --------------------------------- */
	--ck-color-panel-background                   :var(--ck-custom-background);
	--ck-color-panel-border                       :var(--ck-custom-border);
	/* -- Overrides the default .ck-toolbar class colors. --------------------------------------- */
	--ck-color-toolbar-background                 :var(--ck-custom-background);
	--ck-color-toolbar-border                     :var(--ck-custom-border);
	/* -- Overrides the default .ck-tooltip class colors. --------------------------------------- */
	--ck-color-tooltip-background                 :hsl(252, 7%, 14%);
	--ck-color-tooltip-text                       :hsl(0, 0%, 93%);
	/* -- Overrides the default colors used by the ckeditor5-image package. --------------------- */
	--ck-color-image-caption-background           :hsl(0, 0%, 97%);
	--ck-color-image-caption-text                 :hsl(0, 0%, 20%);
	/* -- Overrides the default colors used by the ckeditor5-widget package. -------------------- */
	--ck-color-widget-blurred-border              :hsl(0, 0%, 87%);
	--ck-color-widget-hover-border                :hsl(43, 100%, 68%);
	--ck-color-widget-editable-focus-background   :var(--ck-custom-white);
	/* -- Overrides the default colors used by the ckeditor5-link package. ---------------------- */
	--ck-color-link-default                       :hsl(190, 100%, 75%);
}
.CKEditor-container[data-theme='light'][data-editor='DecoupledEditor-A4']{
	--ck-custom-border        :rgba(96, 98, 102, .6);
	--ck-color-toolbar-border :var(--ck-custom-border);
	--ck-paper-background     :rgba(255, 255, 255, 1);
}
.CKEditor-container[data-editor='DecoupledEditor-A4']{
	box-sizing :border-box;
	margin     :0;
	padding    :0;
	border     :0;
	width      :100%;
	.toolbar{
		width :100%;
	}
	.row-editor{
		display          :flex;
		position         :relative;
		justify-content  :center;
		overflow-y       :auto;
		background-color :var(--ck-custom-background);
		border           :1px solid var(--ck-color-toolbar-border);
		/* 这个高度大约是一张A4纸的高度加上2个border的宽度加上2个A4纸容器的外边距高度. */
		max-height       :calc(29.7cm + 2px + 5rem);
		.editor{
			box-sizing       :border-box;
			box-shadow       :0 0 5px hsla(0, 0%, 0%, .1);
			margin           :2.5rem;
			padding          :2cm 1.2cm;
			border           :1px hsl(0, 0%, 82.7%) solid;
			/*这个高度等于一张A4纸的高度加上2个border的宽度*/
			min-height       :calc(29.7cm + 2px);
			height           :fit-content;
			/*这个宽度等于一张A4纸的宽度加上2个border的宽度*/
			width            :calc(21cm + 2px);
			color            :var(--ck-base-text-color);
			background-color :var(--ck-paper-background);
		}
	}
	.editor-container{
		display         :flex;
		flex-direction  :row;
		flex-wrap       :nowrap;
		position        :relative;
		justify-content :center;
		width           :100%;
	}
}
</style>